package com.artifex.mupdf.viewer

import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.OpenableColumns
import android.util.Base64
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.artifex.mupdf.viewer.databinding.FragmentHomeBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.UUID
import androidx.core.content.edit
import androidx.core.view.MenuProvider
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.File
import java.io.FileOutputStream
import java.io.InputStreamReader
import java.io.OutputStreamWriter

class HomeFragment : Fragment(), MenuProvider {
    private lateinit var binding: FragmentHomeBinding
//    private val viewModel: HomeViewModel by viewModels()

    private val bookPickerLauncher = registerForActivityResult(
        ActivityResultContracts.OpenDocument()
    ) { uri -> uri?.let { handleSelectedBook(it) } }

    fun openBookPicker() {
        bookPickerLauncher.launch(
            arrayOf(
                "application/vnd.ms-xpsdocument",
                "application/oxps",
                "application/x-cbz",
                "application/vnd.comicbook+zip",
                "application/x-fictionbook",
                "application/x-mobipocket-ebook",
                "application/pdf",          // PDF files
                "application/epub+zip",     // EPUB files
                "text/plain",               // Plain text
                "application/msword",       // DOC files
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document" // DOCX
            )
        )
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // Register this fragment as a MenuProvider with the host activity
//        (requireActivity() as ComponentActivity).addMenuProvider(this)
        binding.toolbar.addMenuProvider(this)

        val adapter = BookAdapter(
            onItemClick = { book ->
                // Open the book at last read position
                openBook(book.filePath.toUri())
            },
            onMenuClick = { view, book, position ->
                showBookOptionsMenu(view, book, position)
            }
        )


        binding.recyclerView.apply {
            layoutManager = LinearLayoutManager(requireContext())
            this.adapter = adapter
            addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
        }

        lifecycleScope.launch(Dispatchers.IO) {  // Perform database operations on IO thread
            try {
                val database = AppDatabase.getDatabase(requireContext())
                val books = database.bookDao().getBooks()

                withContext(Dispatchers.Main) {  // Switch back to main thread for UI updates
                    adapter.submitList(books)
                    binding.emptyState.visibility = if (books.isEmpty()) View.VISIBLE else View.GONE
                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    Toast.makeText(requireContext(), "Error loading books", Toast.LENGTH_SHORT)
                        .show()
                }
                Log.e("HomeFragment", "Error loading books", e)
            }
        }

        binding.addBookButton.setOnClickListener {
            openBookPicker()
        }
    }

    private fun handleSelectedBook(uri: Uri) {
        lifecycleScope.launch {
            // open file
            openBook(uri)

            //save book into history
            try {
                // 1. Get permanent read permission
                val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                requireContext().contentResolver.takePersistableUriPermission(uri, takeFlags)

                // 2. Create Book entity with basic info
                val book = Book(
                    id = UUID.randomUUID().toString(),
                    filePath = uri.toString(),
                    title = "",
                    author = "",
                    coverUrl = "",
                    addedDate = System.currentTimeMillis(),
                )

                // 3. Extract metadata in background
                withContext(Dispatchers.IO) {
                    extractAndSaveBookMetadata(book, uri)
                }

                // 4. Show success message
                withContext(Dispatchers.Main) {
                    Toast.makeText(requireContext(), "Book added successfully", Toast.LENGTH_SHORT)
                        .show()
                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    Toast.makeText(
                        requireContext(),
                        "Error adding book: ${e.message}",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
        }
    }

    private suspend fun extractAndSaveBookMetadata(book: Book, uri: Uri) {
        val context = requireContext().applicationContext
        val resolver = context.contentResolver

        // 1. Get basic file info
        val displayName = extractDisplayName(resolver, uri)

        // 3. Update book entity with metadata
        val updatedBook = book.copy(
            title = displayName
        )

        // 4. Save to database
        AppDatabase.getDatabase(context).bookDao().insertBook(updatedBook)
    }

    private fun extractDisplayName(resolver: ContentResolver, uri: Uri): String {
        val projection = arrayOf(
            OpenableColumns.DISPLAY_NAME,
            OpenableColumns.SIZE
        )

        resolver.query(uri, projection, null, null, null)?.use { cursor ->
            if (cursor.moveToFirst()) {
                val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)

                val displayName = cursor.getString(nameIndex)
                val size = cursor.getLong(sizeIndex)
                val extension = displayName.substringAfterLast('.', "").lowercase()

                return displayName
            }
        }

        // Fallback if cursor fails
        val displayName = uri.lastPathSegment ?: "Unknown"
        return displayName;
    }

    private fun deleteBook(book: Book, position: Int) {
        requireContext().getSharedPreferences(
            Base64.encodeToString(
                book.filePath.toByteArray(),
                Base64.NO_WRAP
            ), Context.MODE_PRIVATE
        ).edit { clear() }
        lifecycleScope.launch(Dispatchers.IO) {
            // Get database instance
            val database = AppDatabase.getDatabase(requireContext())
            // Delete directly
            database.bookDao().deleteBookById(book.id)
            val books = database.bookDao().getBooks()
            // Reload or update UI
            withContext(Dispatchers.Main) {
                Toast.makeText(requireContext(), "Book deleted", Toast.LENGTH_SHORT).show()
                // This is functionally identical to the one-liner but more verbose
                val adapter = binding.recyclerView.adapter
                if (adapter is BookAdapter) {
                    adapter.submitList(books)
                }
                binding.emptyState.visibility = if (books.isEmpty()) View.VISIBLE else View.GONE
            }
        }
    }

    private fun openBook(uri: Uri) {
        val intent = Intent(requireContext(), TTSDocumentActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
        intent.action = Intent.ACTION_VIEW
        intent.data = uri
        startActivity(intent)
    }

    private fun showBookOptionsMenu(view: View, book: Book, position: Int) {
        val popup = PopupMenu(requireContext(), view)
        popup.menuInflater.inflate(R.menu.book_item_menu, popup.menu)

        popup.setOnMenuItemClickListener { item ->
            when (item.itemId) {
                R.id.delete -> {
                    deleteBook(book, position)
                    true
                }
                R.id.gbk_to_utf8 -> {
                    Toast.makeText(requireContext(), "Converting", Toast.LENGTH_LONG).show()
                    lifecycleScope.launch(Dispatchers.IO) {
                        gbkToUtf8(book)
                    }
                    true
                }
                else -> false
            }
        }
        popup.show()
    }

    override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
        menuInflater.inflate(R.menu.home_menu, menu)
    }

    override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
        return when (menuItem.itemId) {
            R.id.action_add_book -> {
                openBookPicker()
                true // Consume the event
            }

            // You can handle other menu items here if needed
            else -> false // Let the activity or other fragments handle the event
        }
    }

    private suspend fun gbkToUtf8(book: Book) {
        try {
            val contentResolver = requireContext().contentResolver
            val inputStream = contentResolver.openInputStream(book.filePath.toUri()) ?: return
            val reader = BufferedReader(InputStreamReader(inputStream, "GBK"))
            val output = File.createTempFile(System.currentTimeMillis().toString(), ".txt", requireContext().cacheDir)
            if (!output.exists()) {
                output.createNewFile()
            }
            val writer = BufferedWriter(OutputStreamWriter(FileOutputStream(output), "UTF-8"))
            val buffer = CharArray(1024)
            var count: Int
            while (reader.read(buffer).also { count = it } != -1) {
                writer.write(buffer, 0, count)
            }
            reader.close()
            writer.close()
            // Optionally, update the file in the database to point to the converted one
            val fileUri = Uri.fromFile(output)
            updateBookFileUri(book, fileUri)
            val database = AppDatabase.getDatabase(requireContext())
            val books = database.bookDao().getBooks()

            withContext(Dispatchers.Main) {
                val adapter = binding.recyclerView.adapter
                if (adapter is BookAdapter) {
                    adapter.submitList(books)
                }
                Toast.makeText(
                    requireContext(),
                    "File converted from GBK to UTF-8 successfully",
                    Toast.LENGTH_SHORT
                ).show()
                openBook(fileUri)
            }
        } catch (e: Exception) {
            withContext(Dispatchers.Main) {
                Toast.makeText(
                    requireContext(),
                    "Error converting file encoding: ${e.message}",
                    Toast.LENGTH_SHORT
                ).show()
            }
            Log.e("HomeFragment", "Error converting file encoding", e)
            return
        }
    }
    private suspend fun updateBookFileUri(book: Book, newUri: Uri) {
        // You need the `BookDao` to update the file path
        val database = AppDatabase.getDatabase(requireContext())
        database.bookDao().updateBook(book.copy(filePath = newUri.toString()))
    }
}